#include "InterOpWriterHelper.h"
#include "body.hxx"
#include "common/logger.h"
#include "entity.hxx"
#include "face.hxx"
#include "kernapi.hxx"
#include "lump.hxx"
#include "mmgr.hxx"
#include "pattern_enum.hxx"
#include "shell.hxx"
#include "subshell.hxx"
#include "topology/TopoIterator.hpp"
#include <common/PointT.hpp>
#include <topology/TopoCast.hpp>
#include <topology/TopoTool.hpp>
#include <topology/TopoVertex.hpp>
#include "WriterTopoConvertHelper.h"
#include <occtio/OCCTTool.hpp>
#include "InterOpWriter.h"

AMCAX_EXCHANGE_NAMESPACE_BEGIN

namespace InterOp::WriterConvert
{
    ENTITY_LIST globalFaceList; // 全局列表，用于收集所有FACE

    typedef std::function<void(const AMCAX::TopoShape, ENTITY *parentEntity, ENTITY *subEntity)> ConvertFunction;

    const std::unordered_map<AMCAX::ShapeType, ConvertFunction> CONVERT_FUNCTION_MAP = {
        {AMCAX::ShapeType::Compound, std::bind(WriterConvert::ConvertCompound, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::CompSolid, std::bind(WriterConvert::ConvertCompSolid, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::Solid, std::bind(WriterConvert::ConvertSolid, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::Shell, std::bind(WriterConvert::ConvertShell, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::Face, std::bind(WriterConvert::ConvertFace, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::Wire, std::bind(WriterConvert::ConvertWire, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::Edge, std::bind(WriterConvert::ConvertEdge, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)},
        {AMCAX::ShapeType::Vertex, std::bind(WriterConvert::ConvertVertex, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)}};

    std::string ShapeTypeToString(ShapeType type)
    {
        switch (type)
        {
        case ShapeType::Shape:
            return "Shape";
        case ShapeType::Compound:
            return "Compound";
        case ShapeType::CompSolid:
            return "CompSolid";
        case ShapeType::Solid:
            return "Solid";
        case ShapeType::Shell:
            return "Shell";
        case ShapeType::Face:
            return "Face";
        case ShapeType::Wire:
            return "Wire";
        case ShapeType::Edge:
            return "Edge";
        case ShapeType::Vertex:
            return "Vertex";
        default:
            return "Unknown";
        }
    }

    void Convert(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        
        // InterOp::WriterConvert::globalFaceList.clear();
        if (shape.IsNull())
        {
            LOG_ERROR("shape is null");
            return;
        }
        AMCAX::ShapeType type = shape.Type();
        static int count = 0;
        count++;
        std::string typeName = ShapeTypeToString(type);
        std::string testPath = "D:\\amcax_dev\\modelFiles\\test-output\\";
        bool isOK = AMCAX::OCCTIO::OCCTTool::Write(shape, testPath + std::to_string(count) + "_" + typeName + ".brep", false);

        if (CONVERT_FUNCTION_MAP.find(type) == CONVERT_FUNCTION_MAP.end())
        {
            LOG_ERROR("Corresponding parsing function not found!!");
            return;
        }

        ConvertFunction fun = CONVERT_FUNCTION_MAP.at(type);
        fun(shape, parentEntity, subEntity);
        // TODO: 先创建子类，在通过这里进行关联
        // if (!subEntity) {
        //     LOG_DEBUG("Maybe compound or solid") ;
        //     return ;
        // }

        std::string filePath = "D:\\amcax_dev\\modelFiles\\test\\debug\\catpart\\";
        InterOp::Writer wr; 
        wr.WriterToFile(filePath + "globalEntityList"+ ".sat", globalFaceList);
    }

    void ConvertSubShape(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        for (AMCAX::TopoIterator shapesIter(shape, true, true); shapesIter.More(); shapesIter.Next())
        {
            const auto &subShape = shapesIter.Value();
            Convert(subShape, parentEntity, subEntity);
        }
    }

    void ConvertCompound(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        // NOTE: 是若干拓扑结构的集合 ，在转换时仅仅对子节点进行转换
        // LOG_DEBUG("ready to convert compound!") ;
        ConvertSubShape(shape, parentEntity, subEntity);
    }

    void ConvertCompSolid(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        // NOTE: 是一些Solid的几何，在转换时仅仅对子节点进行转换
        ConvertSubShape(shape, parentEntity, subEntity);
    }

    void ConvertSolid(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {

        // NOTE: 很类似lump
        // interOp 对lump定义：
        if (!is_BODY(parentEntity))
        {
            LOG_ERROR("Parent entity should be lump.");
            return;
        }
        LOG_DEBUG("Ready to create lump.");
        LUMP *lump = ACIS_NEW LUMP;
        subEntity = lump;
        BODY *body = cast_BODY(parentEntity);
        if (!body->lump())
        {
            body->set_lump(lump);
        }
        else
        {
            body->lump()->set_next(lump);
        }

        ENTITY *newEntity = nullptr;
        ConvertSubShape(shape, subEntity, newEntity);
    }

    void ConvertShell(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
       // LOG_DEBUG("ready to convert shell!");
        // NOTE: 上层的父结构应该是 lump 节点
        // if (is_LUMP(parentEntity)) {

        // }
        LUMP *lump = nullptr;
        if (is_BODY(parentEntity))
        {
            // NOTE: 添加一些隔断
            BODY *body = cast_BODY(parentEntity);
            lump = ACIS_NEW LUMP;
            if (!body->lump())
            {
                body->set_lump(lump);
            }
            else
            {
                body->lump()->set_next(lump);
            }
        }
        else if (is_LUMP(parentEntity))
        {
            lump = cast_LUMP(parentEntity);
        }

        SHELL *shell = ACIS_NEW SHELL;
        subEntity = shell;

        if (!lump->shell())
        {
            lump->set_shell(shell);
        }
        else
        {
            lump->shell()->set_next(shell);
        }
        ENTITY *newEntity = nullptr;
        ConvertSubShape(shape, shell, newEntity);
    }

    void ConvertFace(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        // LOG_DEBUG("ready to convert face! ") ;
        // NOTE: 只考虑顶层是Shell的情况
        SHELL *shell = nullptr;
        if (is_BODY(parentEntity))
        {
            // LOG_DEBUG("parent entity is body") ;
            // NOTE: 需从lump到shells一直创建.
            // TODO: 或者从挂在最后一个上面？
            BODY *body = cast_BODY(parentEntity);
            LUMP *lump = ACIS_NEW LUMP;
            if (!body->lump())
            {
                body->set_lump(lump);
            }
            else
            {
                body->lump()->set_next(lump);
            }
            shell = ACIS_NEW SHELL;
            if (!lump->shell())
            {
                lump->set_shell(shell);
            }
            else
            {
                lump->shell()->set_next(shell);
            }
        }
        else if (is_LUMP(parentEntity))
        {
            // LOG_DEBUG("parent entity is lump") ;
            LUMP *lump = cast_LUMP(parentEntity);
            shell = ACIS_NEW SHELL;
            if (!lump->shell())
            {
                lump->set_shell(shell);
            }
            else
            {
                SHELL *current = lump->shell();
                while (current->next() != nullptr)
                {
                    current = current->next();
                }
                current->set_next(shell);
            }
        }
        else if (is_SHELL(parentEntity))
        {
            shell = cast_SHELL(parentEntity);
        }
        else
        {
            LOG_ERROR("unsupport layer.");
            return;
        }
        AMCAX::TopoFace topoFace = AMCAX::TopoCast::Face(shape);
     
        FACE *face = WriterTopoConvertHelper::ConvertFace(topoFace);
        
        
      
        if(face == nullptr)
        {
            LOG_ERROR("face is null");
            return;
        }
        globalFaceList.add(face);

        static int count = 0;
        ENTITY_LIST acisEntitys;
        acisEntitys.add(face);
        count++;
        std::string filePath = "D:\\amcax_dev\\modelFiles\\test\\debug\\catpart\\";
        InterOp::Writer wr; 
        wr.WriterToFile(filePath + std::to_string(count) + ".sat", acisEntitys);

        if (shell && face)
        {
            if (!shell->face())
            {
                shell->set_face(face);
            }
            else
            {
                FACE *current = shell->face();
                while (current->next() != nullptr)
                {
                    current = current->next();
                }
                current->set_next(face);
            }
        }

        ENTITY *newEntity = nullptr;
        //ConvertSubShape(shape, shell, newEntity);
    }

    void ConvertWire(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        FACE *face = nullptr;
        // LOG_DEBUG("ready to convert wire!") ;
        ConvertSubShape(shape, parentEntity, subEntity);
    }

    void ConvertEdge(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {

        // InterOp::WriterTopoConvertHelper::ConvertEdge(TopoCast::Edge(shape));
        //  LOG_DEBUG("ready to convert edge!") ;
        //  ConvertSubShape(shape,entityList) ;
    }

    void ConvertVertex(const AMCAX::TopoShape shape, ENTITY *parentEntity, ENTITY *subEntity)
    {
        // LOG_DEBUG("ready to convert vertex!") ;
        AMCAX::TopoVertex vertex = AMCAX::TopoCast::Vertex(shape);
        AMCAX::Point3 point = AMCAX::TopoTool::Point(vertex);
        LOG_DEBUG("point: {} , {}, {}", point.X(), point.Y(), point.Z());
    }

}

AMCAX_EXCHANGE_NAMESPACE_END